www.gusucode.com > Reach 程序工具箱matlab源码 > Reach/Coreach Tool/src/ReachCoreach.m

    classdef ReachCoreach < handle
    % REACHCOREACH A class that enables performing reachability/coreachability
    % analysis on blocks in a model.
    %
    %   A reachability analysis (reach) finds all blocks and lines that the
    %   given initial blocks affect via control flow or data flow. A
    %   coreachability analysis (coreach) finds all blocks and lines that affect
    %   the given initial blocks via control flow or data flow. After creating a
    %   ReachCoreach object, the reachAll and coreachAll methods can be used to
    %   perform these analyses respectively, and highlight all the
    %   blocks/lines in the reach and coreach.
    %
    % Example:
    %       open_system('ReachCoreachDemo_2011')
    %       r = ReachCoreach('ReachCoreachDemo_2011');
    %
    %   % Perform a reachability analysis:
    %       r.reachAll({'ReachCoreachDemo_2011/In2'},[]);
    %
    %   % Clear highlighting:
    %       r.clear();
    %
    %   % Change the highlighting colors
    %       r.setColor('blue', 'magenta')
    %
    %   % Perform a coreachability analysis:
    %       r.coreachAll({'ReachCoreachDemo_2011/Out2', {'ReachCoreachDemo_2011/Out3'},{});
    %
    %   % Perform a slice:
    %       r.slice();
    
    properties
        RootSystemName      % Simulink model name (or top-level system name).
        RootSystemHandle    % Handle of top level subsystem.
        
        ReachedObjects      % List of blocks and lines reached.
        CoreachedObjects    % List of blocks and lines coreached.
        
        TraversedPorts      % Ports already traversed in the reach operation.
        TraversedPortsCo    % Ports already traversed in the coreach operation.
        
        dsmMap              % Map of data store names to data store memory blocks
        dsrMap              % Map of data store names to data store read blocks
        dswMap              % Map of data store names to data store write blocks
        
        stvMap              % Map of goto tag names to goto tag visibility blocks
        sgMap               % Map of goto tag names to goto blocks
        sfMap               % Map of goto tag names to from blocks
    end
    
    properties(Access = private)
        PortsToTraverse     % Ports remaining to traverse in the reach operation.
        PortsToTraverseCo   % Ports remaining to traverse in the coreach operation.
        
        RecurseCell         % Ports being reached in the main Reach loop
        
        Color               % Foreground color of highlight.
        BGColor             % Background color of highlight.
        
        dsmFlag             % Flag that determines uniqueness of DataStoreNames
        gtvFlag             % Flag that determines uniqueness of Goto Tags
        
        busCreatorBlockMap  % Map of all of the blocks a bused signal from a creator passes through
        busSelectorBlockMap % Map of all of the blocks a bused signal to a selector passes through
        
        busCreatorExitMap   % Map of all of the exits a bused signal from a creator passes through
        busSelectorExitMap  % Map of all of the exits a bused signal to a selector passes through
        
        hiliteFlag          % Flag indicating whether to immediately highlight after a RCR operation
    end
    
    methods
        function object = ReachCoreach(RootSystemName)
            % REACHCOREACH Constructor for the ReachCoreach object.
            %
            %   Input:
            %       RootSystemName  Parameter name of the top level system in
            %                       the model hierarchy the reach/coreach
            %                       operations are to be run on.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj = ReachCoreach('ModelName')
            
            % Check parameter RootSystemName
            % 1) Ensure the model corresponding to RootSystemName is open
            try
                assert(ischar(RootSystemName));
                assert(bdIsLoaded(RootSystemName));
            catch
                disp(['Error using ' mfilename ':' newline ...
                    'Invalid RootSystemName. Model corresponding ' ...
                    'to RootSystemName may not be loaded or name is invalid.'])
                return
            end
            
            % 2) Ensure that the parameter given is the top level of the
            % model
            try
                assert(strcmp(RootSystemName, bdroot(RootSystemName)))
            catch
                disp(['Error using ' mfilename ':' newline ...
                    'Invalid RootSystemName. Given RootSystemName is not ' ...
                    'the root level of its model.'])
                return
            end
            
            % Initialize a new instance of ReachCoreach.
            object.RootSystemName = RootSystemName;
            object.RootSystemHandle = get_param(RootSystemName, 'handle');
            object.ReachedObjects = [];
            object.CoreachedObjects = [];
            object.Color = 'red';
            object.BGColor = 'yellow';
            object.dsmMap = containers.Map;
            object.dsrMap = containers.Map;
            object.dswMap = containers.Map;
            object.stvMap = containers.Map;
            object.sgMap = containers.Map;
            object.sfMap = containers.Map;
            object.gtvFlag = 1;
            object.dsmFlag = 1;
            object.hiliteFlag = 1;
            object.busCreatorBlockMap = containers.Map();
            object.busSelectorBlockMap = containers.Map();
            
            % Make a map of the scoped gotos by tag
            temp = {};
            scopedGotos = find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'Goto', 'TagVisibility', 'scoped');
            scopedGotos = [scopedGotos; find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'Goto', 'TagVisibility', 'global')];
            for i=1:length(scopedGotos)
                tag = get_param(scopedGotos{i}, 'GotoTag');
                temp{end+1} = tag;
                try
                    object.sgMap(tag) = [object.sgMap(tag); scopedGotos{i}];
                catch
                    object.sgMap(tag) = {scopedGotos{i}};
                end
            end
            %             if (length(temp) == length(unique(temp)))&&(object.gtvFlag == 1)
            %                 object.gtvFlag = 1;
            %             else
            %                 object.gtvFlag = 0;
            %             end
            
            % Make a map of the scoped froms by tag
            temp = {};
            scopedFroms = find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'From');
            for i=1:length(scopedFroms)
                tag = get_param(scopedFroms{i}, 'GotoTag');
                temp{end+1} = tag;
                try
                    object.sfMap(tag) = [object.sfMap(tag); scopedFroms{i}];
                catch
                    object.sfMap(tag) = {scopedFroms{i}};
                end
            end
            %             if (length(temp) == length(unique(temp)))&&(object.gtvFlag == 1)
            %                 object.gtvFlag = 1;
            %             else
            %                 object.gtvFlag = 0;
            %             end
            
            % Make a map of the scoped tag visibility blocks by tag, and
            % additionally check for repeated scoped tag names
            temp = {};
            scopedTags = find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'GotoTagVisibility');
            for i=1:length(scopedTags)
                tag = get_param(scopedTags{i}, 'GotoTag');
                temp{end+1} = tag;
                try
                    object.stvMap(tag) = [object.stvMap(tag); scopedTags{i}];
                catch
                    object.stvMap(tag) = {scopedTags{i}};
                end
            end
            %             if (length(temp) == length(unique(temp)))&&(object.gtvFlag == 1)
            %                 object.gtvFlag = 1;
            %             else
            %                 object.gtvFlag = 0;
            %             end
            
            reads = find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'DataStoreRead');
            for i=1:length(reads);
                dsName = get_param(reads{i}, 'DataStoreName');
                try
                    object.dsrMap(dsName) = [object.dsrMap(dsName); reads{i}];
                catch
                    object.dsrMap(dsName) = {reads{i}};
                end
            end
            
            writes = find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'DataStoreWrite');
            for i=1:length(writes);
                dsName = get_param(writes{i}, 'DataStoreName');
                try
                    object.dswMap(dsName) = [object.dswMap(dsName); writes{i}];
                catch
                    object.dswMap(dsName) = {writes{i}};
                end
            end
            
            temp = {};
            mems = find_system(RootSystemName, 'FollowLinks', 'on', ...
                'BlockType', 'DataStoreMemory');
            for i=1:length(mems);
                dsName = get_param(mems{i}, 'DataStoreName');
                temp{end+1} = dsName;
                try
                    object.dsmMap(dsName) = [object.dsmMap(dsName); mems{i}];
                catch
                    object.dsmMap(dsName) = {mems{i}};
                end
            end
            if (length(temp) == length(unique(temp)))
                object.dsmFlag = 1;
            else
                object.dsmFlag = 0;
            end
        end

        function [fgcolor, bgcolor] = getColor(object)
            % GETCOLOR Get the highlight colours for the reach/coreach.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %
            %   Outputs:
            %       fgcolor Foreground colour.
            %       bgcolor Background colour.
            %
            %   Example:
            %       obj.getColor()
            fgcolor = object.Color;
            bgcolor = object.BGColor;
        end
        
        function setColor(object, color1, color2)
            % SETCOLOR Set the highlight colours for the reach/coreach.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %       color1  Parameter for the highlight foreground colour.
            %               Accepted values are 'red', 'green', 'blue', 'cyan',
            %               'magenta', 'yellow', 'black', 'white'.
            %
            %       color2  Parameter for the highlight background colour.
            %               Accepted values are 'red', 'green', 'blue', 'cyan',
            %               'magenta', 'yellow', 'black', 'white'.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.setColor('red', 'blue')
            
            % Ensure that the parameters are strings
            try
                assert(ischar(color1))
                assert(ischar(color2))
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' Invalid color(s). Accepted colors are ''red'', ''green'', ' ...
                    '''blue'', ''cyan'', ''magenta'', ''yellow'', ''white'', and ''black''.'])
                return
            end
            
            % Ensure that the colours selected are acceptable
            try
                acceptedColors = {'cyan', 'red', 'blue', 'green', 'magenta', ...
                    'yellow', 'white', 'black'};
                assert(isempty(setdiff(color1, acceptedColors)))
                assert(isempty(setdiff(color2, acceptedColors)))
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' Invalid color(s). Accepted colours are ''red'', ''green'', ' ...
                    '''blue'', ''cyan'', ''magenta'', ''yellow'', ''white'', and ''black''.'])
                return
            end
            % Record current open system
            initialOpenSystem = gcs;
            
            % Set the desired colours for highlighting
            object.Color = color1;
            object.BGColor = color2;
            
            % Make initial system the active window
            open_system(initialOpenSystem)
        end
        
        function setHiliteFlag(object, flag)
            % SETHILITEFLAG Set hiliteFlag object property. Determines whether
            % to hilite objects or not.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %       flag    Boolean value to set the flag to.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.setHiliteFlag(true)
            
            if flag == 0
                object.hiliteFlag = flag;
            else
                object.hiliteFlag = 1;
            end
        end
        
        function hiliteObjects(object)
            % HILITEOBJECTS Highlight the reached/coreached blocks and lines.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.hiliteObjects()
            
            % Keep track of currently opened windows
            openSys = find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Open', 'on');
            
            % Hilite reached/coreached elements
            HILITE_DATA = struct('HiliteType', 'user2', 'ForegroundColor', object.Color, 'BackgroundColor', object.BGColor);
            set_param(0, 'HiliteAncestorsData', HILITE_DATA);
            warningID = 'Simulink:blocks:HideContents';
            warning('off', warningID);
            % Clear previous hilite (Fix for 2016b)
            hilite_system_notopen(object.ReachedObjects, 'none');
            hilite_system_notopen(object.CoreachedObjects, 'none');
            % Apply new hilite
            hilite_system_notopen(object.ReachedObjects, 'user2');
            hilite_system_notopen(object.CoreachedObjects, 'user2');
            warning('on', warningID);
            
            % Close windows that weren't open before
            allOpenSys = find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Open', 'on');
            sysToClose = setdiff(allOpenSys, openSys);
            close_system(sysToClose); % Close Simulink systems
            sfclose('all'); % Close Stateflow
        end
        
        function slice(object)
            % SLICE Isolate the reached/coreached blocks by removing
            % unhighlighted blocks.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.slice()
            
            % Ensure that there is a selection before slicing.
            try
                assert(~isempty(object.ReachedObjects)||~isempty(object.CoreachedObjects))
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' There are no reached/coreached objects' ...
                    ' to slice.'])
                return
            end
            
            % Record current open system
            initialOpenSystem = gcs;
            
            openSys = find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Open', 'on');
            
            % Remove links
            subsystems = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'SubSystem');
            for i = 1:length(subsystems)
                linkStatus = get_param(subsystems{i}, 'LinkStatus');
                if strcmp(linkStatus, 'resolved')
                    set_param(subsystems{i}, 'LinkStatus', 'inactive');
                elseif strcmp(linkStatus, 'implicit')
                    % If a subsystem higher in the hierarchy is linked
                    % find it and make link inactive
                    flag = 1;
                    linkedSys = subsystems{i};
                    while flag
                        linkedSys = get_param(linkedSys, 'parent');
                        linkStatus = get_param(linkedSys, 'LinkStatus');
                        if strcmp(linkStatus, 'resolved')
                            set_param(linkedSys, 'LinkStatus', 'inactive');
                            flag = 0;
                        end
                    end
                end
            end
            
            allBlocks = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'block');
            toKeep = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'line', 'HiliteAncestors', 'user2');
            toKeep = [toKeep; find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'block', 'HiliteAncestors', 'user2')];
            
            blocksToDelete = setdiff(allBlocks, toKeep);
            warningID = 'MATLAB:DELETE:FileNotFound';
            warning('off', warningID);
            
            for i = 1:length(blocksToDelete)
                try
                    delete_block(blocksToDelete(i));
                catch E
                    if ~strcmp(E.identifier, 'Simulink:Commands:InvSimulinkObjHandle')
                        error(E);
                    end
                end
            end
            
            allLines = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'line');
            linesToDelete = setdiff(allLines, toKeep);
            for i = 1:length(linesToDelete)
                try
                    delete_block(linesToDelete(i));
                catch E
                    if ~strcmp(E.identifier, 'Simulink:Commands:InvSimulinkObjHandle')
                        error(E);
                    end
                end
            end
            
            warning('on', warningID);
            brokenLines = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'line', 'DstBlockHandle', -1);
            brokenLines = [brokenLines; find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'line', 'SrcBlockHandle', -1)];
            delete_line(brokenLines);
            
            %ground unconnected lines
            GroundAndTerminatePorts(object.RootSystemName);
            
            subsToCheck = find_system(object.RootSystemName, 'BlockType', 'SubSystem');
            for i = 1:length(subsToCheck)
                GroundAndTerminatePorts(subsToCheck{i});
            end
            
            allOpenSys = find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Open', 'on');
            sysToClose = setdiff(allOpenSys, openSys);
            close_system(sysToClose);
            sfclose('all');
            
            object.clear();
            
            % Make initial system the active window
            if ~isempty(find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Name', initialOpenSystem))
                open_system(initialOpenSystem)
            end
        end
        
        function clear(object)
            % CLEAR Remove all reach/coreach highlighting.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.clear()
            
            % Record current open system
            initialOpenSystem = gcs;
            
            % Clear highlighting
            openSys = find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Open', 'on');
            hilitedObjects = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'line', 'HiliteAncestors', 'user2');
            hilitedObjects = [hilitedObjects; find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'On', 'type', 'block', 'HiliteAncestors', 'user2')];
            hilite_system_notopen(hilitedObjects, 'none');
            object.ReachedObjects = [];
            object.CoreachedObjects = [];
            object.TraversedPorts = [];
            object.TraversedPortsCo = [];
            allOpenSys = find_system(object.RootSystemName, 'FollowLinks', 'on', 'BlockType', 'SubSystem', 'Open', 'on');
            sysToClose = setdiff(allOpenSys, openSys);
            close_system(sysToClose);
            
            % Make initial system the active window
            open_system(initialOpenSystem)
        end
        
        function reachAll(object, selection, lines)
            % REACHALL Reach from a selection of blocks.
            %
            %   Inputs:
            %       object      ReachCoreach object.
            %       selection   Cell array of strings representing the full
            %                   names of blocks.
            %       lines       Array of line handles.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.reachAll({'ModelName/In1', 'ModelName/SubSystem/Out2'}, [])
            
            % Check object parameter RootSystemName
            % 1) Ensure the model corresponding to RootSystemName is open
            try
                assert(ischar(object.RootSystemName));
                assert(bdIsLoaded(object.RootSystemName));
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' Invalid RootSystemName. Model corresponding ' ...
                    'to RootSystemName may not be loaded or name is invalid.'])
                return
            end
            
            % 2) Check that model M is unlocked
            %             try
            %                 assert(strcmp(get_param(bdroot(object.RootSystemName), 'Lock'), 'off'))
            %             catch E
            %                 if strcmp(E.identifier, 'MATLAB:assert:failed') || ...
            %                         strcmp(E.identifier, 'MATLAB:assertion:failed')
            %                     disp(['Error using ' mfilename ':' newline ...
            %                         ' File is locked.'])
            %                     return
            %                 else
            %                     disp(['Error using ' mfilename ':' newline ...
            %                         ' Invalid RootSystemName.'])
            %                     return
            %                 end
            %             end
            
            % Check that selection is of type 'cell'
            try
                assert(iscell(selection));
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' Invalid cell argument "selection".'])
                return
            end
            
            % Record current open system
            initialOpenSystem = gcs;
            
            % Get the ports/blocks of selected blocks that are special
            % cases
            for i = 1:length(selection)
                % Check that the elements of selection are existing blocks
                % in model RootSystemName
                try
                    assert(strcmp(get_param(selection{i}, 'type'), 'block'));
                    assert(strcmp(bdroot(selection{i}), object.RootSystemName));
                catch
                    disp(['Error using ' mfilename ':' newline ...
                        selection{i} ' is not a block in system ' object.RootSystemName '.'])
                    break
                end
                selectionType = get_param(selection{i}, 'BlockType');
                if strcmp(selectionType, 'SubSystem')
                    % Get all outgoing interface from subsystem, and add
                    % blocks to reach, as well as ports to the list of ports
                    % to traverse
                    outBlocks = object.getInterfaceOut(selection{i});
                    for j = 1:length(outBlocks)
                        object.ReachedObjects(end + 1) = get_param(outBlocks{j}, 'handle');
                        ports = get_param(outBlocks{j}, 'PortHandles');
                        object.PortsToTraverse = [object.PortsToTraverse ports.Outport];
                    end
                    moreBlocks = find_system(selection{i}, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on');
                    for j = 1:length(moreBlocks)
                        object.ReachedObjects(end + 1) = get_param(moreBlocks{j}, 'handle');
                    end
                    lines = find_system(selection{i}, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'line');
                    object.ReachedObjects = [object.ReachedObjects lines.'];
                    morePorts = find_system(selection{i}, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'port');
                    if iscolumn(morePorts)
                        morePorts = morePorts.';
                    end
                    portsToExclude = get_param(selection{i}, 'PortHandles');
                    portsToExclude = portsToExclude.Outport;
                    morePorts = setdiff(morePorts, portsToExclude);
                    object.TraversedPorts = [object.TraversedPorts morePorts];
                elseif strcmp(selectionType, 'Outport')
                    portNum = get_param(selection{i}, 'Port');
                    parent = get_param(selection{i}, 'parent');
                    if ~isempty(get_param(parent, 'parent'))
                        portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                            'type', 'port', 'parent', parent, 'PortType', 'outport', 'PortNumber', str2num(portNum));
                        object.ReachedObjects(end + 1) = get_param(parent, 'handle');
                        object.PortsToTraverse(end + 1) = portSub;
                    end
                elseif strcmp(selectionType, 'GotoTagVisibility')
                    % Add goto and from blocks to reach, and ports to list to traverse
                    associatedBlocks = findGotoFromsInScopeRCR(object, selection{i}, object.gtvFlag);
                    for j = 1:length(associatedBlocks)
                        object.ReachedObjects(end + 1) = get_param(associatedBlocks{j}, 'handle');
                        ports = get_param(associatedBlocks{j}, 'PortHandles');
                        object.PortsToTraverse = [object.PortsToTraverse ports.Outport];
                    end
                elseif strcmp(selectionType, 'DataStoreMemory')
                    % Add read and write blocks to reach, and ports to list
                    % to traverse
                    associatedBlocks = findReadWritesInScopeRCR(object, selection{i}, object.dsmFlag);
                    for j = 1:length(associatedBlocks)
                        object.ReachedObjects(end + 1) = get_param(associatedBlocks{j}, 'handle');
                        ports = get_param(associatedBlocks{j}, 'PortHandles');
                        object.PortsToTraverse = [object.PortsToTraverse ports.Outport];
                    end
                elseif strcmp(selectionType, 'DataStoreWrite')
                    % Add read blocks to reach, and ports to list to traverse
                    reads = findReadsInScopeRCR(object, selection{i}, object.dsmFlag);
                    for j = 1:length(reads)
                        object.ReachedObjects(end + 1) = get_param(reads{j}, 'handle');
                        ports = get_param(reads{j}, 'PortHandles');
                        object.PortsToTraverse = [object.PortsToTraverse ports.Outport];
                    end
                    mem = findDataStoreMemoryRCR(object, selection{i}, object.dsmFlag);
                    if ~isempty(mem)
                        object.ReachedObjects(end + 1) = get_param(mem, 'Handle');
                    end
                elseif strcmp(selectionType, 'DataStoreRead')
                    mem = findDataStoreMemoryRCR(object, selection{i}, object.dsmFlag);
                    if ~isempty(mem)
                        object.ReachedObjects(end + 1) = get_param(mem, 'Handle');
                    end
                elseif strcmp(selectionType, 'Goto')
                    % Add from blocks to reach, and ports to list to traverse
                    froms = findFromsInScopeRCR(object, selection{i}, object.gtvFlag);
                    for j = 1:length(froms)
                        object.ReachedObjects(end + 1) = get_param(froms{j}, 'handle');
                        ports = get_param(froms{j}, 'PortHandles');
                        object.PortsToTraverse = [object.PortsToTraverse ports.Outport];
                    end
                    tag = findVisibilityTagRCR(object, selection{i}, object.gtvFlag);
                    if ~isempty(tag)
                        object.ReachedObjects(end + 1) = get_param(tag, 'Handle');
                    end
                elseif strcmp(selectionType, 'From')
                    tag = findVisibilityTagRCR(object, selection{i}, object.gtvFlag);
                    if ~isempty(tag)
                        object.ReachedObjects(end + 1) = get_param(tag, 'Handle');
                    end
                elseif strcmp(selectionType, 'BusCreator')
                    busInports = get_param(selection{i}, 'PortHandles');
                    busInports = busInports.Inport;
                    for j = 1:length(busInports)
                        line = get_param(busInports(j), 'line');
                        signalName = get_param(line, 'Name');
                        if isempty(signalName)
                            portNum = get_param(busInports(j), 'PortNumber');
                            signalName = ['signal' num2str(portNum)];
                        end
                        busPort = get_param(selection{i}, 'PortHandles');
                        busPort = busPort.Outport;
                        [path, exit] = object.traverseBusForwards(selection{i}, busPort, signalName, []);
                        object.TraversedPorts = [object.TraversedPorts path];
                        blockList = object.busCreatorBlockMap;
                        blockList = blockList(selection{i});
                        object.ReachedObjects = [object.ReachedObjects blockList];
                        object.PortsToTraverse = [object.PortsToTraverse exit];
                    end
                elseif (strcmp(selectionType, 'EnablePort') || ...
                        strcmp(selectionType, 'ActionPort') || ...
                        strcmp(selectionType, 'TriggerPort') || ...
                        strcmp(selectionType, 'WhileIterator') || ...
                        strcmp(selectionType, 'ForEach') || ...
                        strcmp(selectionType, 'ForIterator'))
                    % Add everything in a subsystem to the reach if one
                    % of the listed block types is in the selection
                    object.reachEverythingInSub(get_param(selection{i}, 'parent'))
                end
                % Add blocks to reach from selection, and their ports to the
                % list to traverse
                object.ReachedObjects(end + 1) = get_param(selection{i}, 'handle');
                ports = get_param(selection{i}, 'PortHandles');
                object.PortsToTraverse = [object.PortsToTraverse ports.Outport];
            end
            
            for i = 1:length(lines)
                object.PortsToTraverse = [object.PortsToTraverse get_param(lines(i), 'SrcPortHandle')];
            end
            
            
            % Reach from each in the list of ports to traverse
            while ~isempty(object.PortsToTraverse)
                object.RecurseCell = setdiff(object.PortsToTraverse, object.TraversedPorts);
                object.PortsToTraverse = [];
                while ~isempty(object.RecurseCell)
                    port = object.RecurseCell(end);
                    object.RecurseCell(end) = [];
                    reach(object, port)
                end
                %object.PortsToTraverse = setdiff(object.PortsToTraverse, object.TraversedPorts);
            end
            
            % Get foreach blocks
            forEach = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'ForEach');
            for i = 1:length(forEach)
                system = get_param(forEach{i}, 'parent');
                sysObjects = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on');
                sysObjects = setdiff(sysObjects, get_param(system, 'handle'));
                if ~isempty(intersect(sysObjects, object.ReachedObjects))
                    if isempty(intersect(get_param(forEach{i}, 'Handle'), object.ReachedObjects))
                        object.ReachedObjects(end + 1) = get_param(forEach{i}, 'Handle');
                    end
                end
            end
            
            % Highlight all objects reached
            if object.hiliteFlag
                object.hiliteObjects();
            end
            
            % Make initial system the active window
            open_system(initialOpenSystem)
        end
        
        function coreachAll(object, selection, selLines)
            % COREACHALL Coreach from a selection of blocks.
            %
            %   Inputs:
            %       object      ReachCoreach object.
            %       selection   Cell array of strings representing the full
            %                   names of blocks.
            %       selLines    Array of line handles.
            %
            %   Outputs:
            %       N/A
            %
            %   Example:
            %       obj.coreachAll({'ModelName/In1', 'ModelName/SubSystem/Out2'})
            
            % Check object parameter RootSystemName
            % 1) Ensure the model corresponding to RootSystemName is open
            try
                assert(ischar(object.RootSystemName));
                assert(bdIsLoaded(object.RootSystemName));
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' Invalid RootSystemName. Model corresponding ' ...
                    'to RootSystemName may not be loaded or name is invalid.'])
                return
            end
            
            % Check that selection is of type 'cell'
            try
                assert(iscell(selection));
            catch
                disp(['Error using ' mfilename ':' newline ...
                    ' Invalid cell argument "selection".'])
                return
            end
            
            % Record current open system
            initialOpenSystem = gcs;
            
            % Get the ports/blocks of selected blocks that are special
            % cases
            for i = 1:length(selection)
                % Check that the elements of selection are existing blocks
                % in model RootSystemName
                try
                    assert(strcmp(get_param(selection{i}, 'type'), 'block'));
                    assert(strcmp(bdroot(selection{i}), object.RootSystemName));
                catch
                    disp(['Error using ' mfilename ':' newline ...
                        selection{i} ' is not a block in system ' object.RootSystemName '.'])
                    break
                end
                selectionType = get_param(selection{i}, 'BlockType');
                if strcmp(selectionType, 'SubSystem')
                    % Get all incoming interface to subsystem, and add
                    % blocks to coreach, as well as ports to the list of ports
                    % to traverse
                    inBlocks = object.getInterfaceIn(selection{i});
                    for j = 1:length(inBlocks)
                        object.CoreachedObjects(end + 1) = get_param(inBlocks{j}, 'handle');
                        ports = get_param(inBlocks{j}, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Inport];
                    end
                    moreBlocks = find_system(selection{i}, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on');
                    for j = 1:length(moreBlocks)
                        object.CoreachedObjects(end + 1) = get_param(moreBlocks{j}, 'handle');
                    end
                    lines = find_system(selection{i}, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'line');
                    object.CoreachedObjects = [object.CoreachedObjects lines.'];
                    morePorts = find_system(selection{i}, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'port');
                    if iscolumn(morePorts)
                        morePorts = morePorts.';
                    end
                    portsSub = get_param(selection{i}, 'PortHandles');
                    portsToExclude = [portsSub.Inport portsSub.Trigger portsSub.Enable portsSub.Ifaction];
                    morePorts = setdiff(morePorts, portsToExclude);
                    object.TraversedPortsCo = [object.TraversedPortsCo morePorts];
                elseif strcmp(selectionType, 'Inport')
                    portNum = get_param(selection{i}, 'Port');
                    parent = get_param(selection{i}, 'parent');
                    if ~isempty(get_param(parent, 'parent'))
                        portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                            'type', 'port', 'parent', parent, 'PortType', 'inport', 'PortNumber', str2num(portNum));
                        object.CoreachedObjects(end + 1) = get_param(parent, 'handle');
                        object.PortsToTraverseCo(end + 1) = portSub;
                    end
                elseif strcmp(selectionType, 'GotoTagVisibility')
                    % Add goto and from blocks to coreach, and ports to list to
                    % traverse
                    associatedBlocks = findGotoFromsInScopeRCR(object, selection{i}, object.gtvFlag);
                    for j = 1:length(associatedBlocks)
                        object.CoreachedObjects(end + 1) = get_param(associatedBlocks{j}, 'handle');
                        ports = get_param(associatedBlocks{j}, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Inport];
                    end
                elseif strcmp(selectionType, 'DataStoreMemory')
                    % Add read and write blocks to coreach, and ports to list
                    % to traverse
                    associatedBlocks = findReadWritesInScopeRCR(object, selection{i}, object.dsmFlag);
                    for j = 1:length(associatedBlocks)
                        object.CoreachedObjects(end + 1) = get_param(associatedBlocks{j}, 'handle');
                        ports = get_param(associatedBlocks{j}, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Inport];
                    end
                elseif strcmp(selectionType, 'From')
                    % Add goto blocks to coreach, and ports to list to
                    % traverse
                    gotos = findGotosInScopeRCR(object, selection{i}, object.gtvFlag);
                    for j = 1:length(gotos)
                        object.CoreachedObjects(end + 1) = get_param(gotos{j}, 'handle');
                        ports = get_param(gotos{j}, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Inport];
                    end
                    tag = findVisibilityTagRCR(object, selection{i}, object.gtvFlag);
                    if ~isempty(tag)
                        object.CoreachedObjects(end + 1) = get_param(tag, 'Handle');
                    end
                elseif strcmp(selectionType, 'Goto')
                    tag = findVisibilityTagRCR(object, selection{i}, object.gtvFlag);
                    if ~isempty(tag)
                        object.CoreachedObjects(end + 1) = get_param(tag, 'Handle');
                    end
                elseif strcmp(selectionType, 'DataStoreRead')
                    % Add write blocks to coreach, and ports to list to
                    % traverse
                    writes = findWritesInScopeRCR(object, selection{i}, object.dsmFlag);
                    for j = 1:length(writes)
                        object.CoreachedObjects(end + 1) = get_param(writes{j}, 'handle');
                        ports = get_param(writes{j}, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Inport];
                    end
                    mem = findDataStoreMemoryRCR(object, selection{i}, object.dsmFlag);
                    if ~isempty(mem)
                        object.CoreachedObjects(end + 1) = get_param(mem, 'Handle');
                    end
                elseif strcmp(selectionType, 'DataStoreWrite')
                    mem = findDataStoreMemoryRCR(object, selection{i}, object.dsmFlag);
                    if ~isempty(mem)
                        object.CoreachedObjects(end + 1) = get_param(mem, 'Handle');
                    end
                elseif strcmp(selectionType, 'BusSelector')
                    busOutports = get_param(selection{i}, 'PortHandles');
                    busOutports = busOutports.Outport;
                    for j = 1:length(busOutports)
                        portNum = get_param(busOutports(j), 'PortNumber');
                        signal = get_param(selection{i}, 'OutputSignals');
                        signal = regexp(signal, ',', 'split');
                        signal = signal{portNum};
                        busPort=get_param(selection{i}, 'PortHandles');
                        [path, blockList, exit] = object.traverseBusBackwards(busPort.Inport, signal, [], []);
                        object.TraversedPortsCo = [object.TraversedPortsCo path];
                        object.CoreachedObjects = [object.CoreachedObjects blockList];
                        object.PortsToTraverseCo = [object.PortsToTraverseCo exit];
                    end
                elseif strcmp(selectionType, 'TriggerPort')
                    parent = get_param(selection{i}, 'parent');
                    portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                        'type', 'port', 'parent', parent, 'PortType', 'trigger');
                    object.PortsToTraverseCo = [object.PortsToTraverseCo portSub];
                elseif strcmp(selectionType, 'EnablePort')
                    parent = get_param(selection{i}, 'parent');
                    portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                        'type', 'port', 'parent', parent, 'PortType', 'enable');
                    object.PortsToTraverseCo = [object.PortsToTraverseCo portSub];
                elseif strcmp(selectionType, 'ActionPort')
                    parent = get_param(selection{i}, 'parent');
                    portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                        'type', 'port', 'parent', parent, 'PortType', 'ifaction');
                    object.PortsToTraverseCo = [object.PortsToTraverseCo portSub];
                elseif strcmp(selectionType, 'WhileIterator') || strcmp(selectionType, 'ForIterator') || strcmp(selectionType, 'ForEach')
                    toCoreach = getInterfaceOut(object, get_param(selection{i}, 'parent'));
                    for j = 1:length(toCoreach)
                        ports = get_param(toCoreach{j}, 'PortHandles');
                        object.CoreachedObjects(end+1) = get_param(toCoreach{j}, 'Handle');
                        inports = ports.Inport;
                        for k = 1:length(inports)
                            object.PortsToTraverseCo(end + 1) = inports(k);
                        end
                    end
                    ins = find_system(get_param(selection{i}, 'parent'), 'SearchDepth', 1, 'BlockType', 'Outport');
                    for j = 1:length(ins)
                        ports = get_param(ins{j}, 'PortHandles');
                        object.CoreachedObjects(end+1) = get_param(ins{j}, 'Handle');
                        inports = ports.Inport;
                        for k = 1:length(inports)
                            object.PortsToTraverseCo(end + 1) = inports(k);
                        end
                    end
                end
                % Add blocks to coreach from selection, and their ports to the
                % list to traverse
                object.CoreachedObjects(end + 1) = get_param(selection{i}, 'handle');
                ports = get_param(selection{i}, 'PortHandles');
                object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Inport];
                object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Enable];
                object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Trigger];
                object.PortsToTraverseCo = [object.PortsToTraverseCo ports.Ifaction];
            end
            
            for i = 1:length(selLines)
                object.PortsToTraverseCo = [object.PortsToTraverseCo get_param(selLines(i), 'DstPortHandle')];
            end
            
            flag = true;
            while flag
                % Coreach from each in the list of ports to traverse
                while ~isempty(object.PortsToTraverseCo)
                    port = object.PortsToTraverseCo(end);
                    object.PortsToTraverseCo(end) = [];
                    coreach(object, port)
                end
                % Add any iterators in the coreach to blocks coreached and
                % their ports to list to traverse
                iterators = findIterators(object);
                if ~isempty(iterators)
                    for i = 1:length(iterators)
                        ports = get_param(iterators{i}, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo, ports.Inport];
                        object.CoreachedObjects(end + 1) = get_param(iterators{i}, 'Handle');
                    end
                end
                % Add any trigger, enable, or action ports and their
                % respective blocks to the coreach and their ports to the
                % list to traverse
                object.findSpecialPorts();
                % Keep iterating through until there are no more
                % blocks/ports being added
                if isempty(object.PortsToTraverseCo)
                    flag = false;
                end
            end
            
            % Highlight the coreached objects
            if object.hiliteFlag
                object.hiliteObjects();
            end
            
            % Make initial system the active window
            open_system(initialOpenSystem)
        end
    end
    
    methods(Access = private)
        function reach(object, port)
            % REACH Find the next ports to call the reach from, and add all
            % objects encountered to Reached Objects.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %       port
            %
            %   Output:
            %       N/A
            
            % Check if this port was already traversed
            if any(object.TraversedPorts == port)
                return
            end
            
            % Get block port belongs to
            block = get_param(port, 'parent');
            
            % Mark this port as traversed
            object.TraversedPorts(end + 1) = port;
            
            % Get line from the port, and then get the destination blocks
            line = get_param(port, 'line');
            if (line == -1)
                return
            end
            object.ReachedObjects(end + 1) = line;
            nextBlocks = get_param(line, 'DstBlockHandle');
            
            for i = 1:length(nextBlocks)
                if (nextBlocks(i) == -1)
                    continue
                end
                % Add block to list of reached objects
                object.ReachedObjects(end + 1) = nextBlocks(i);
                
                % Get blocktype for switch case
                blockType = get_param(nextBlocks(i), 'BlockType');
                
                % Handle the coreaching of various blocks differently
                switch blockType
                    case 'Goto'
                        % Handles the case where the next block is a goto.
                        % Finds all froms and adds their outgoing ports to
                        % the list of ports to traverse
                        froms = findFromsInScopeRCR(object, getfullname(nextBlocks(i)), object.gtvFlag);
                        for j = 1:length(froms)
                            object.ReachedObjects(end + 1) = get_param(froms{j}, 'handle');
                            outport = get_param(froms{j}, 'PortHandles');
                            outport = outport.Outport;
                            if ~isempty(outport)
                                object.PortsToTraverse(end + 1) = outport;
                            end
                        end
                        % Adds associated goto tag visibility block to the
                        % reach
                        tag = findVisibilityTagRCR(object, getfullname(nextBlocks(i)), object.gtvFlag);
                        if ~isempty(tag)
                            object.ReachedObjects(end + 1) = get_param(tag, 'Handle');
                        end
                    case 'DataStoreWrite'
                        % Handles the case where the next block is a data store
                        % write. Finds all data store reads and adds their
                        % outgoing ports to the list of ports to traverse
                        reads = findReadsInScopeRCR(object, getfullname(nextBlocks(i)), object.dsmFlag);
                        for j = 1:length(reads)
                            object.ReachedObjects(end + 1) = get_param(reads{j}, 'Handle');
                            outport = get_param(reads{j}, 'PortHandles');
                            outport = outport.Outport;
                            object.PortsToTraverse(end + 1) = outport;
                        end
                        % Adds associated data store memory block to the
                        % reach
                        mem = findDataStoreMemoryRCR(object, getfullname(nextBlocks(i)), object.dsmFlag);
                        if ~isempty(mem)
                            object.ReachedObjects(end + 1) = get_param(mem, 'Handle');
                        end
                        
                    case 'SubSystem'
                        % Handles the case where the next block is a
                        % subsystem. Adds corresponding inports inside
                        % subsystem to reach and adds their outgoing ports
                        % to list of ports to traverse
                        isVariant = get_param(nextBlocks(i), 'variant');
                        if strcmp(isVariant, 'on')
                            dstPorts = get_param(line, 'DstPortHandle');
                            for j = 1:length(dstPorts)
                                portNum = get_param(dstPorts(j), 'PortNumber');
                                portType = get_param(dstPorts(j), 'PortType');
                                % This if statement checks for trigger, enable,
                                % or ifaction ports
                                if strcmp(portType, 'trigger')
                                    object.reachEverythingInSub(getfullname(nextBlocks(i)));
                                    triggerBlocks = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', ...
                                        'FollowLinks', 'on', 'BlockType', 'TriggerPort');
                                    object.ReachedObjects(end + 1) = triggerBlocks;
                                elseif strcmp(portType, 'enable')
                                    object.reachEverythingInSub(getfullname(nextBlocks(i)));
                                    enableBlocks = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', ...
                                        'FollowLinks', 'on', 'BlockType', 'EnablePort');
                                    object.ReachedObjects(end + 1) = enableBlocks;
                                elseif strcmp(portType, 'ifaction')
                                    object.reachEverythingInSub(getfullname(nextBlocks(i)));
                                    actionBlocks = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', ...
                                        'FollowLinks', 'on', 'BlockType', 'ActionPort');
                                    object.ReachedObjects(end + 1) = actionBlocks;
                                else
                                    inport = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', ...
                                        'BlockType', 'Inport', 'Port', num2str(portNum));
                                    if ~isempty(inport)
                                        object.ReachedObjects(end + 1) = get_param(inport, 'Handle');
                                        inportNum = get_param(inport, 'Port');
                                        subsystemVariants = find_system(nextBlocks(i), 'SearchDepth', 1, 'BlockType', 'SubSystem');
                                        for k = 2:length(subsystemVariants)
                                            variantInport = find_system(subsystemVariants(k), 'SearchDepth', 1, 'BlockType', 'Inport', 'Port', inportNum);
                                            object.ReachedObjects(end + 1) = get_param(variantInport, 'Handle');
                                            outport = get_param(variantInport, 'PortHandles');
                                            outport = outport.Outport;
                                            object.PortsToTraverse(end + 1) = outport;
                                        end
                                    end
                                end
                            end
                        else
                            dstPorts = get_param(line, 'DstPortHandle');
                            for j = 1:length(dstPorts)
                                if get_param(get_param(dstPorts(j), 'Parent'), 'Handle') == nextBlocks(i)
                                    portNum = get_param(dstPorts(j), 'PortNumber');
                                    portType = get_param(dstPorts(j), 'PortType');
                                    % This if statement checks for trigger, enable,
                                    % or ifaction ports
                                    if strcmp(portType, 'trigger')
                                        object.reachEverythingInSub(getfullname(nextBlocks(i)));
                                        triggerBlocks = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', ...
                                            'FollowLinks', 'on', 'BlockType', 'TriggerPort');
                                        if ~isempty(triggerBlocks)
                                            object.ReachedObjects(end + 1) = triggerBlocks;
                                        end
                                    elseif strcmp(portType, 'enable')
                                        object.reachEverythingInSub(getfullname(nextBlocks(i)));
                                        enableBlocks = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', ...
                                            'FollowLinks', 'on', 'BlockType', 'EnablePort');
                                        if ~isempty(enableBlocks)
                                            object.ReachedObjects(end + 1) = enableBlocks;
                                        end
                                    elseif strcmp(portType, 'ifaction')
                                        object.reachEverythingInSub(getfullname(nextBlocks(i)));
                                        actionBlocks = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', ...
                                            'FollowLinks', 'on', 'BlockType', 'ActionPort');
                                        if ~isempty(actionBlocks)
                                            object.ReachedObjects(end + 1) = actionBlocks;
                                        end
                                    else
                                        inport = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', ...
                                            'BlockType', 'Inport', 'Port', num2str(portNum));
                                        if ~isempty(inport)
                                            object.ReachedObjects(end + 1) = get_param(inport, 'Handle');
                                            outport = get_param(inport, 'PortHandles');
                                            outport = outport.Outport;
                                            object.PortsToTraverse(end + 1) = outport;
                                        end
                                    end
                                end
                            end
                        end
                        
                    case 'Outport'
                        % Handles the case where the next block is an
                        % outport. Provided the outport isn't at top level,
                        % add subsystem outport belongs to to the reach and
                        % add corresponding subsystem port of the outport to
                        % list of ports to traverse
                        portNum = get_param(nextBlocks(i), 'Port');
                        parent = get_param(nextBlocks(i), 'parent');
                        grandParent = get_param(parent, 'parent');
                        if ~strcmp(grandParent, '') && ~strcmp(grandParent, object.RootSystemName)
                            isVariant = get_param(grandParent, 'Variant');
                        else
                            isVariant = 'off';
                        end
                        if strcmp(isVariant, 'on')
                            object.ReachedObjects(end + 1) = get_param(parent, 'handle');
                            nextOutport = find_system(grandParent, 'SearchDepth', 1, 'BlockType', 'Outport', 'Port', portNum);
                            object.ReachedObjects(end + 1) = get_param(nextOutport{1}, 'handle');
                            portSub = find_system(get_param(grandParent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                                'type', 'port', 'parent', grandParent, 'PortType', 'outport', 'PortNumber', str2num(portNum));
                            object.ReachedObjects(end + 1) = get_param(grandParent, 'handle');
                            object.PortsToTraverse(end + 1) = portSub;
                        else
                            if ~isempty(get_param(parent, 'parent'))
                                portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                                    'type', 'port', 'parent', parent, 'PortType', 'outport', 'PortNumber', str2num(portNum));
                                object.ReachedObjects(end + 1) = get_param(parent, 'handle');
                                object.PortsToTraverse(end + 1) = portSub;
                            end
                        end
                        
                    case {'WhileIterator', 'ForIterator'}
                        % Get all blocks/ports in the subsystem, then reach
                        % the blocks the outports, gotos, and writes connect
                        % to outside of the system.
                        parent = get_param(block, 'parent');
                        object.reachEverythingInSub(parent);
                        
                    case 'BusCreator'
                        % Handles the case where the next block is a bus
                        % creator. Follows the signal going into bus creator
                        % and highlights the path through the bused signal
                        % and out to its next block once the bus is
                        % separated.
                        
                        dstPort = get_param(line, 'DstPortHandle');
                        for j = 1:length(dstPort)
                            signalName = get_param(line, 'Name');
                            if isempty(signalName)
                                portNum = get_param(dstPort(j), 'PortNumber');
                                signalName = ['signal' num2str(portNum)];
                            end
                            if strcmp(get_param(get_param(dstPort(j), 'parent'), 'BlockType'), 'BusCreator')
                                busPort = get_param(nextBlocks(i), 'PortHandles');
                                busPort = busPort.Outport;
                                [path, exit] = object.traverseBusForwards(block, busPort, signalName, []);
                                object.TraversedPorts = [object.TraversedPorts path];
                                blockList = object.busCreatorBlockMap;
                                blockList = blockList(block);
                                object.ReachedObjects = [object.ReachedObjects blockList];
                                object.PortsToTraverse = [object.PortsToTraverse exit];
                            end
                        end
                        
                    case 'BusAssignment'
                        assignedSignals = get_param(nextBlocks(i), 'AssignedSignals');
                        assignedSignals = regexp(assignedSignals, ',', 'split');
                        dstPorts = get_param(line, 'DstPortHandle');
                        blockInports = get_param(nextBlocks(i), 'PortHandles');
                        busPort = blockInports.Outport;
                        blockInports = blockInports.Inport;
                        inter = intersect(blockInports, dstPorts);
                        portNumbers = get_param(inter, 'PortNumber');
                        for j = 1:length(portNumbers)
                            if (portNumbers(j) ~= 1)
                                % For each port, iterate reaching through nested
                                % buses
                                if iscell(portNumbers)
                                    signalToReach = assignedSignals{portNumbers{j} - 1};
                                else
                                    signalToReach = assignedSignals{portNumbers(j) - 1};
                                end
                                flag = true;
                                while flag
                                    [path, blockList, exit] = object.traverseBusForwards(busPort, signalToReach, [], []);
                                    object.TraversedPorts = [object.TraversedPorts path];
                                    object.ReachedObjects = [object.ReachedObjects blockList];
                                    dots = strfind(signalToReach, '.');
                                    if isempty(dots)
                                        flag = false;
                                    else
                                        signalToReach = signalToReach(1:dots(end)-1);
                                    end
                                    busPort = exit;
                                end
                            else
                                ports = get_param(nextBlocks(i), 'PortHandles');
                                outports = ports.Outport;
                                for k = 1:length(outports)
                                    object.PortsToTraverse(end + 1) = outports(k);
                                end
                                exit = [];
                            end
                            object.PortsToTraverse = [object.PortsToTraverse exit];
                        end
                        
                    case 'If'
                        % Handles the case where the next block is an if
                        % block. Reaches each port where the corresponding
                        % condition is referenced and the else port
                        ports = get_param(nextBlocks(i), 'PortHandles');
                        outports = ports.Outport;
                        dstPort = get_param(line, 'DstPortHandle');
                        for j = 1:length(dstPort)
                            if strcmp(get_param(get_param(dstPort(i),'parent'), 'BlockType'), 'If')
                                portNum = get_param(dstPort(i), 'PortNumber');
                                cond = ['u' num2str(portNum)];
                                expressions = get_param(nextBlocks(i), 'ElseIfExpressions');
                                if ~isempty(expressions)
                                    expressions = regexp(expressions, ',', 'split');
                                    expressions = [{get_param(nextBlocks(i), 'IfExpression')} expressions];
                                else
                                    expressions = {};
                                    expressions{end + 1} = get_param(nextBlocks(i), 'IfExpression');
                                end
                                elseFlag = false;
                                for j = 1:length(expressions)
                                    if regexp(expressions{j}, cond)
                                        elseFlag = true;
                                        for k = 1:length(expressions)+1-j
                                            object.PortsToTraverse(end + 1) = outports(k+j-1);
                                        end
                                    end
                                end
                                if strcmp(get_param(nextBlocks(i), 'ShowElse'), 'on')
                                    if elseFlag
                                        object.PortsToTraverse(end + 1) = outports(end);
                                    end
                                end
                            end
                        end
                        
                    otherwise
                        % Otherwise case, simply adds outports of block to
                        % the list of ports to traverse
                        ports = get_param(nextBlocks(i), 'PortHandles');
                        outports = ports.Outport;
                        for j = 1:length(outports)
                            object.PortsToTraverse(end + 1) = outports(j);
                        end
                end
            end
        end
        
        function coreach(object, port)
            % COREACH Find the next ports to find the coreach from, and add all
            % objects encountered to coreached objects.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %       port
            %
            %   Outputs:
            %       N/A
            
            % Check if this port was already traversed
            if any(object.TraversedPortsCo == port)
                return
            end
            
            % Get the block port it belongs to
            block = get_param(port, 'parent');
            
            % Mark this port as traversed
            object.TraversedPortsCo(end + 1) = port;
            
            % Get the line from the port, and then get the destination blocks
            line = get_param(port, 'line');
            if (line == -1)
                return
            end
            object.CoreachedObjects(end + 1) = line;
            nextBlocks = get_param(line, 'SrcBlockHandle');
            
            for i = 1:length(nextBlocks)
                if (nextBlocks(i) == -1)
                    break
                end
                % Add the block to list of coreached objects
                object.CoreachedObjects(end + 1) = nextBlocks(i);
                
                % Get blocktype for switch case
                blockType = get_param(nextBlocks(i), 'BlockType');
                
                % Handle the coreaching of various blocks differently
                switch blockType
                    case 'From'
                        % Handles the case where the next block is a from
                        % block. Finds all gotos associated with the from
                        % block, adds them to the coreach blocks, then adds
                        % their respective inports to the list of ports to
                        % traverse
                        gotos = findGotosInScopeRCR(object, getfullname(nextBlocks(i)), object.gtvFlag);
                        for j = 1:length(gotos)
                            object.CoreachedObjects(end + 1) = get_param(gotos{j}, 'handle');
                            inport = get_param(gotos{j}, 'PortHandles');
                            inport = inport.Inport;
                            object.PortsToTraverseCo(end + 1) = inport;
                        end
                        % Adds the associated goto tag visibility block to
                        % the list of coreached objects
                        tag = findVisibilityTagRCR(object, getfullname(nextBlocks(i)), object.gtvFlag);
                        if ~isempty(tag)
                            object.CoreachedObjects(end + 1) = get_param(tag, 'Handle');
                        end
                        
                    case 'DataStoreRead'
                        % Handles the case where the next block is a data
                        % store read block. Finds all gotos associated with
                        % the write block, adds them to the coreached
                        % blocks, then adds their respective inports to the
                        % list of ports to traverse
                        writes = findWritesInScopeRCR(object, getfullname(nextBlocks(i)), object.dsmFlag);
                        for j = 1:length(writes)
                            object.CoreachedObjects(end + 1) = get_param(writes{j}, 'Handle');
                            inport = get_param(writes{j}, 'PortHandles');
                            inport = inport.Inport;
                            object.PortsToTraverseCo(end + 1) = inport;
                        end
                        % Adds the associated data store memory block to
                        % the list of coreached objects
                        mem = findDataStoreMemoryRCR(object, getfullname(nextBlocks(i)), object.dsmFlag);
                        if ~isempty(mem)
                            object.CoreachedObjects(end + 1) = get_param(mem, 'Handle');
                        end
                        
                    case 'SubSystem'
                        % Handles the case where the next block is a
                        % subsystem. Finds outport block corresponding to
                        % the outport of the subsystem, adds it to the
                        % list of coreached objects, then adds its inport to
                        % the list of inports to traverse
                        srcPorts = get_param(line, 'SrcPortHandle');
                        isVariant = get_param(nextBlocks(i), 'Variant');
                        if strcmp(isVariant, 'on')
                            for j = 1:length(srcPorts)
                                portNum = get_param(srcPorts(j), 'PortNumber');
                                outport = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', ...
                                    'BlockType', 'Outport', 'Port', num2str(portNum));
                                if ~isempty(outport)
                                    object.CoreachedObjects(end + 1) = get_param(outport, 'Handle');
                                    outportNum = get_param(outport, 'Port');
                                    subsystemVariants = find_system(nextBlocks(i), 'SearchDepth', 1, 'BlockType', 'SubSystem');
                                    for k = 2:length(subsystemVariants)
                                        variantInport = find_system(subsystemVariants(k), 'SearchDepth', 1, 'BlockType', 'Outport', 'Port', outportNum);
                                        object.CoreachedObjects(end + 1) = get_param(variantInport, 'Handle');
                                        inport = get_param(variantInport, 'PortHandles');
                                        inport = inport.Inport;
                                        object.PortsToTraverseCo(end + 1) = inport;
                                    end
                                end
                            end
                        else
                            for j = 1:length(srcPorts)
                                portNum = get_param(srcPorts(j), 'PortNumber');
                                outport = find_system(nextBlocks(i), 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Outport', 'Port', num2str(portNum));
                                if ~isempty(outport)
                                    object.CoreachedObjects(end + 1) = get_param(outport, 'Handle');
                                    inport = get_param(outport, 'PortHandles');
                                    inport = inport.Inport;
                                    object.PortsToTraverseCo(end + 1) = inport;
                                end
                            end
                        end
                        
                    case 'Inport'
                        % Handles the case where the next block is an
                        % inport. If the inport is not top level, it adds
                        % the parent subsystem to the list of coreached
                        % objects, then adds the corresponding inport on the
                        % subsystem to the list of ports to traverse
                        portNum = get_param(nextBlocks(i), 'Port');
                        parent = get_param(nextBlocks(i), 'parent');
                        grandParent = get_param(parent, 'parent');
                        if ~strcmp(grandParent, '') && ~strcmp(grandParent, object.RootSystemName)
                            isVariant = get_param(grandParent, 'Variant');
                        else
                            isVariant = 'off';
                        end
                        if strcmp(isVariant, 'on')
                            object.CoreachedObjects(end + 1) = get_param(parent, 'handle');
                            nextInport = find_system(grandParent, 'SearchDepth', 1, 'BlockType', 'Inport', 'Port', portNum);
                            object.CoreachedObjects(end + 1) = get_param(nextInport{1}, 'handle');
                            portSub = find_system(get_param(grandParent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                                'type', 'port', 'parent', grandParent, 'PortType', 'inport', 'PortNumber', str2num(portNum));
                            object.CoreachedObjects(end + 1) = get_param(grandParent, 'handle');
                            object.PortsToTraverseCo(end + 1) = portSub;
                        else
                            if ~isempty(get_param(parent, 'parent'))
                                portSub = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                                    'type', 'port', 'parent', parent, 'PortType', 'inport', 'PortNumber', str2num(portNum));
                                object.CoreachedObjects(end + 1) = get_param(parent, 'handle');
                                object.PortsToTraverseCo(end + 1) = portSub;
                            end
                        end
                        
                    case 'BusSelector'
                        % Handles the case where the next block is a bus
                        % selector. Follows the signal going into the bus
                        % and adds the path through the bus to the list of
                        % coreached objects. Adds the corresponding exit
                        % port on the bus creator to the list of ports to
                        % traverse
                        portBus = get_param(line, 'SrcPortHandle');
                        portNum = get_param(portBus, 'PortNumber');
                        signal = get_param(nextBlocks(i), 'OutputSignals');
                        signal = regexp(signal, ',', 'split');
                        signal = signal{portNum};
                        busPort=get_param(nextBlocks(i), 'PortHandles');
                        [path, blockList, exit] = object.traverseBusBackwards(busPort.Inport, signal, [], []);
                        object.TraversedPortsCo = [object.TraversedPortsCo path];
                        object.CoreachedObjects = [object.CoreachedObjects blockList];
                        object.PortsToTraverseCo = [object.PortsToTraverseCo exit];
                        
                    case 'If'
                        % Handles the case where the next block is an if
                        % block. Adds ports with conditions corresponding to
                        % the conditions associated with teh outport the
                        % current port leads into to the list of ports to
                        % traverse
                        srcPort = get_param(line, 'SrcPortHandle');
                        portNum = get_param(srcPort, 'PortNumber');
                        expressions = get_param(nextBlocks(i), 'ElseIfExpressions');
                        if ~isempty(expressions)
                            expressions = regexp(expressions, ', ', 'split');
                            expressions = [{get_param(nextBlocks(i), 'IfExpression')} expressions];
                        else
                            expressions = {};
                            expressions{end + 1} = get_param(nextBlocks(i), 'IfExpression');
                        end
                        if portNum > length(expressions)
                            % Else case
                            ifPorts = get_param(nextBlocks(i), 'PortHandles');
                            ifPorts = ifPorts.Inport;
                            condsToCoreach = zeros(1, length(ifPorts));
                            for j = 1:length(expressions)
                                conds = regexp(expressions{j}, 'u[1-9]+', 'match');
                                for k = 1:length(conds)
                                    c = conds{k};
                                    condsToCoreach(str2num(c(2:end))) = 1;
                                end
                                
                            end
                            object.PortsToTraverseCo = [object.PortsToTraverseCo ifPorts(logical(condsToCoreach))];
                        else
                            conditions = regexp(expressions{portNum}, 'u[1-9]+', 'match');
                            for j = 1:length(conditions)
                                cond = conditions{j};
                                cond = cond(2:end);
                                ifPorts = get_param(nextBlocks(i), 'PortHandles');
                                ifPorts = ifPorts.Inport;
                                object.PortsToTraverseCo(end + 1) = ifPorts(str2num(cond));
                            end
                        end
                    case 'ForIterator'
                        toCoreach = getInterfaceOut(object, get_param(nextBlocks(i), 'parent'));
                        for j = 1:length(toCoreach)
                            ports = get_param(toCoreach{j}, 'PortHandles');
                            object.CoreachedObjects(end+1) = get_param(toCoreach{j}, 'Handle');
                            inports = ports.Inport;
                            for k = 1:length(inports)
                                object.PortsToTraverseCo(end + 1) = inports(k);
                            end
                        end
                        ins = find_system(get_param(nextBlocks(i), 'parent'), 'SearchDepth', 1, 'BlockType', 'Outport');
                        for j = 1:length(ins)
                            ports = get_param(ins{j}, 'PortHandles');
                            object.CoreachedObjects(end+1) = get_param(ins{j}, 'Handle');
                            inports = ports.Inport;
                            for k = 1:length(inports)
                                object.PortsToTraverseCo(end + 1) = inports(k);
                            end
                        end
                        
                    otherwise
                        % Otherwise case, simply adds the inports of the block
                        % to the list of ports to traverse.
                        ports = get_param(nextBlocks(i), 'PortHandles');
                        inports = ports.Inport;
                        for j = 1:length(inports)
                            object.PortsToTraverseCo(end + 1) = inports(j);
                        end
                end
            end
        end
        
        function iterators = findIterators(object)
            % FINDITERATORS Find all while and for iterators that need to be
            % coreached.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %       port
            %
            %   Outputs:
            %       N/A
            
            iterators = {};
            candidates = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'WhileIterator');
            candidates = [candidates find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'ForIterator')];
            for i = 1:length(candidates)
                system = get_param(candidates{i}, 'parent');
                sysObjects = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on');
                sysObjects = setdiff(sysObjects, system);
                if ~isempty(intersect(sysObjects, object.CoreachedObjects))
                    if isempty(intersect(get_param(candidates{i}, 'Handle'), object.CoreachedObjects))
                        iterators{end + 1} = candidates{i};
                    end
                end
            end
        end
        
        function findSpecialPorts(object)
            % FINDSPECIALPORTS Find all actionport, foreach, triggerport, and
            % enableport blocks and adds them to the coreach, as well as adding
            % their corresponding port in the parent subsystem block to the list
            % of ports to traverse.
            %
            %   Input:
            %       object  ReachCoreach object.
            %
            %   Outputs:
            %       N/A
            
            forEach = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'ForEach');
            triggerPorts = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'TriggerPort');
            actionPorts = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'ActionPort');
            enablePorts = find_system(object.RootSystemName, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'EnablePort');
            excludeBlocks = [forEach; triggerPorts; actionPorts; enablePorts];
            toExclude=[];
            for i = 1:length(excludeBlocks)
                toExclude(end + 1) = get_param(excludeBlocks{i}, 'handle');
            end
            
            for i = 1:length(actionPorts)
                system = get_param(actionPorts{i}, 'parent');
                sysObjects = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on');
                sysObjects = setdiff(sysObjects, get_param(system, 'handle'));
                sysObjects = setdiff(sysObjects, toExclude);
                if ~isempty(intersect(sysObjects, object.CoreachedObjects))
                    if isempty(intersect(get_param(actionPorts{i}, 'Handle'), object.CoreachedObjects))
                        object.CoreachedObjects(end + 1) = get_param(actionPorts{i}, 'Handle');
                        sysPorts = get_param(system, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo sysPorts.Ifaction];
                    end
                end
            end
            
            for i = 1:length(triggerPorts)
                system = get_param(triggerPorts{i}, 'parent');
                sysObjects = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on');
                sysObjects = setdiff(sysObjects, get_param(system, 'handle'));
                sysObjects = setdiff(sysObjects, toExclude);
                if ~isempty(intersect(sysObjects, object.CoreachedObjects))
                    if isempty(intersect(get_param(triggerPorts{i}, 'Handle'), object.CoreachedObjects))
                        object.CoreachedObjects(end + 1) = get_param(triggerPorts{i}, 'Handle');
                        sysPorts = get_param(system, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo sysPorts.Trigger];
                    end
                end
            end
            
            for i = 1:length(enablePorts)
                system = get_param(enablePorts{i}, 'parent');
                sysObjects = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on');
                sysObjects = setdiff(sysObjects, get_param(system, 'handle'));
                sysObjects = setdiff(sysObjects, toExclude);
                if ~isempty(intersect(sysObjects, object.CoreachedObjects))
                    if isempty(intersect(get_param(enablePorts{i}, 'Handle'), object.CoreachedObjects))
                        object.CoreachedObjects(end + 1) = get_param(enablePorts{i}, 'Handle');
                        sysPorts = get_param(system, 'PortHandles');
                        object.PortsToTraverseCo = [object.PortsToTraverseCo sysPorts.Enable];
                    end
                end
            end
            
            for i = 1:length(forEach)
                system = get_param(forEach{i}, 'parent');
                sysObjects = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on');
                sysObjects = setdiff(sysObjects, get_param(system, 'handle'));
                sysObjects = setdiff(sysObjects, toExclude);
                if ~isempty(intersect(sysObjects, object.CoreachedObjects))
                    if isempty(intersect(get_param(forEach{i}, 'Handle'), object.CoreachedObjects))
                        object.CoreachedObjects(end + 1) = get_param(forEach{i}, 'Handle');
                    end
                end
            end
        end
        
        function reachEverythingInSub(object, system)
            % REACHEVERYTHINGINSUB Add all blocks and outports of blocks in the
            % subsystem to the lists of reached objects. Also find all interface
            % going outward (outports, gotos, froms) and find the next
            % blocks/ports as if being reached by the main reach function.
            %
            %   Inputs:
            %       object ReachCoreach object.
            %       system
            %
            %   Outputs:
            %       N/A
            
            blocks = find_system(system, 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'block');
            
            % Excludes trigger, enable, and action port blocks (they are
            % added in main function)
            blocksToExclude = find_system(system, 'FindAll', 'on', 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', ...
                'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'block', 'BlockType', 'EnablePort');
            blocksToExclude = [blocksToExclude; find_system(system, 'FindAll', 'on', 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', ...
                'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'block', 'BlockType', 'TriggerPort')];
            blocksToExclude = [blocksToExclude; find_system(system, 'FindAll', 'on', 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', ...
                'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'block', 'BlockType', 'ActionPort')];
            blocks = setdiff(blocks, blocksToExclude);
            
            for i = 1:length(blocks)
                object.ReachedObjects(end + 1) = blocks(i);
            end
            lines = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'line');
            object.ReachedObjects = [object.ReachedObjects lines.'];
            ports = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'FindAll', 'on', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'type', 'port');
            if iscolumn(ports)
                ports = ports.';
            end
            portsToExclude = get_param(system, 'PortHandles');
            portsToExclude = portsToExclude.Outport;
            ports = setdiff(ports, portsToExclude);
            object.TraversedPorts = [object.TraversedPorts ports];
            
            % Handles outports the same as the reach function
            outports = find_system(system, 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Outport');
            for j = 1:length(outports)
                portNum = get_param(outports{j}, 'Port');
                parent = get_param(outports{j}, 'parent');
                if ~isempty(get_param(parent, 'parent'))
                    port = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                        'type', 'port', 'parent', parent, 'PortType', 'outport', 'PortNumber', str2num(portNum));
                    object.ReachedObjects(end + 1) = get_param(parent, 'handle');
                    object.PortsToTraverse(end + 1) = port;
                end
            end
            
            % Handles gotos the same as the reach function
            gotos = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Goto');
            gotosToIgnore = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Goto', 'TagVisibility', 'local');
            gotos = setdiff(gotos, gotosToIgnore);
            for j = 1:length(gotos)
                froms = findFromsInScopeRCR(object, gotos{j}, object.gtvFlag);
                for k = 1:length(froms)
                    object.ReachedObjects(end + 1) = get_param(froms{k}, 'handle');
                    outport = get_param(froms{k}, 'PortHandles');
                    outport = outport.Outport;
                    object.PortsToTraverse(end + 1) = outport;
                end
                tag = findVisibilityTagRCR(object, gotos{j}, object.gtvFlag);
                if ~isempty(tag)
                    if iscell(tag)
                        tag=tag{1};
                    end
                    object.ReachedObjects(end + 1) = get_param(tag, 'Handle');
                end
            end
            
            % Handles writes the same as the reach function
            writes = find_system(system, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreWrite');
            for j = 1:length(writes)
                reads = findReadsInScopeRCR(object, writes{j}, object.dsmFlag);
                for k = 1:length(reads)
                    object.ReachedObjects(end + 1) = get_param(reads{k}, 'Handle');
                    outport = get_param(reads{k}, 'PortHandles');
                    outport = outport.Outport;
                    object.PortsToTraverse(end + 1) = outport;
                end
                mem = findDataStoreMemoryRCR(object, writes{j}, object.dsmFlag);
                if ~isempty(mem)
                    if iscell(mem)
                        mem=mem{1};
                    end
                    object.ReachedObjects(end + 1) = get_param(mem, 'Handle');
                end
            end
            
            %object.PortsToTraverse = setdiff(object.PortsToTraverse, object.TraversedPorts);
        end
        
        function blocks = getInterfaceIn(object, subsystem)
            % GETINTERFACEIN Get all the source blocks for the subsystem,
            % including Gotos and Data Store Writes.
            %
            %   Inputs:
            %       object      ReachCoreach object.
            %       subsystem
            %
            %   Outputs:
            %       blocks
            
            blocks = {};
            gotos = {};
            writes = {};
            froms = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'From');
            allTags = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'GotoTagVisibility');
            for i = 1:length(froms)
                gotos = [gotos; findGotosInScopeRCR(object, froms{i}, object.gtvFlag)];
                tag = findVisibilityTagRCR(object, froms{i}, object.gtvFlag);
                tag = setdiff(tag, allTags);
                if ~isempty(tag)
                    if iscell(tag)
                        tag = tag{1};
                    end
                    object.CoreachedObjects(end + 1) = get_param(tag, 'Handle');
                end
            end
            gotos = setdiff(gotos, find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Goto'));
            
            reads = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreRead');
            allMems = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreMemory');
            for i = 1:length(reads)
                writes = [writes; findWritesInScopeRCR(object, reads{i}, object.dsmFlag)];
                mem = findDataStoreMemoryRCR(object, reads{i}, object.dsmFlag);
                mem = setdiff(mem, allMems);
                if ~isempty(mem)
                    if iscell(mem)
                        mem = mem{1};
                    end
                    object.CoreachedObjects(end + 1) = get_param(mem, 'Handle');
                end
            end
            writes = setdiff(writes, find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreWrite'));
            
            implicits = [gotos writes];
            for i = 1:length(implicits)
                name = getfullname(implicits{i});
                lcs = intersect(name, getfullname(subsystem));
                if ~strcmp(lcs, getfullname(subsystem))
                    blocks{end + 1} = implicits{i};
                end
            end
        end
        
        function blocks = getInterfaceOut(object, subsystem)
            % GETINTERFACEOUT Get all the destination blocks for the subsystem,
            % including Froms and Data Store Reads.
            %
            %   Inputs:
            %       object      ReachCoreach object.
            %       subsystem
            %
            %   Output:
            %       blocks
            
            blocks = {};
            froms = {};
            reads = {};
            gotos = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Goto');
            allTags = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'GotoTagVisibility');
            for i = 1:length(gotos)
                if ~strcmp(get_param(gotos{i}, 'TagVisibility'), 'local')
                    froms = [froms; findFromsInScopeRCR(object, gotos{i}, object.gtvFlag)];
                    tag = findVisibilityTagRCR(object, gotos{i}, object.gtvFlag);
                    tag = setdiff(tag, allTags);
                    if ~isempty(tag)
                        if iscell(tag)
                            tag = tag{1};
                        end
                        object.ReachedObjects(end + 1) = get_param(tag, 'Handle');
                    end
                end
            end
            froms = setdiff(froms, find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'From'));
            
            writes = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreWrite');
            allMems = find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreMemory');
            for i = 1:length(writes)
                reads = [reads; findReadsInScopeRCR(object, writes{i}, object.dsmFlag)];
                mem = findDataStoreMemoryRCR(object, writes{i}, object.dsmFlag);
                mem = setdiff(mem, allMems);
                if ~isempty(mem)
                    if iscell(mem)
                        mem=mem{1};
                    end
                    object.ReachedObjects(end + 1) = get_param(mem, 'Handle');
                end
            end
            reads = setdiff(reads, find_system(subsystem, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'DataStoreRead'));
            
            implicits = [froms reads];
            for i = 1:length(implicits)
                name = getfullname(implicits{i});
                lcs = intersect(name, getfullname(subsystem));
                if ~strcmp(lcs, getfullname(subsystem))
                    blocks{end + 1} = implicits{i};
                end
            end
        end
        
        function [path, exit] = traverseBusForwards(object, creator, oport, signal, path)
            % TRAVERSEBUSFORWARDS Go until a Bus Creator is encountered. Then,
            % return the path taken there as well as the exiting port.
            %
            %   Inputs:
            %       object  ReachCoreach object.
            %       creator
            %       oport
            %       signal
            %       path
            %
            %   Outputs:
            %       path
            %       exit
            
            exit = [];
            for g = 1:length(oport)
                parentBlock = get_param(get_param(oport(g), 'parent'), 'Handle');
                if strcmp(get_param(parentBlock, 'BlockType'), 'SFunction');
                    object.addToMappedArray('busCreatorExitMap', creator, oport(g))
                    break
                end
                
                if ismember(oport(g), path)
                    break
                end
                
                object.addToMappedArray('busCreatorBlockMap', creator, parentBlock)
                portline = get_param(oport(g), 'Line');
                
                try
                    dstBlocks = get_param(portline, 'DstBlockHandle');
                catch
                    break
                end
                
                object.addToMappedArray('busCreatorBlockMap', creator, portline)
                path(end + 1) = oport(g);
                
                % If the bus ends early (not at Bus Selector) output empty
                % dest and exit
                if isempty(dstBlocks)
                    dest = [];
                    exit = [];
                end
                
                % For each of the destination blocks
                for h = 1:length(dstBlocks)
                    next = dstBlocks(h);
                    blockType = get_param(next, 'BlockType');
                    
                    switch blockType
                        case 'BusCreator'
                            % If the next block is a Bus Creator, call the
                            % traverse function recursively
                            signalName = get_param(portline, 'Name');
                            
                            % Get all destination ports from the signal
                            % line into the Bus Creator
                            dstPort = get_param(portline, 'DstPortHandle');
                            nextports = get_param(next, 'PortHandles');
                            inports = nextports.Inport;
                            dstPort = intersect(dstPort, inports);
                            if isempty(signalName)
                                for i = 1:length(dstPort)
                                    portNum = get_param(dstPort(g), 'PortNumber');
                                    signalName = ['signal' num2str(portNum) '.' signal];
                                    [path, intermediate] = object.traverseBusForwards(creator, nextports.Outport, ...
                                        signalName, path);
                                    path = [path intermediate];
                                    path = unique(path);
                                    for j = 1:length(intermediate)
                                        [tempPath, tempExit] = object.traverseBusForwards(creator, intermediate(j), ...
                                            signal, path);
                                        exit = [exit tempExit];
                                        path = [path, tempPath];
                                        path = unique(path);
                                    end
                                end
                            else
                                signalName = [signalName '.' signal];
                                [path, intermediate] = object.traverseBusForwards(creator, nextports.Outport, ...
                                    signalName, path);
                                for i = 1:length(intermediate)
                                    [tempPath, tempExit] = object.traverseBusForwards(creator, intermediate(i), ...
                                        signal, path);
                                    exit = [exit tempExit];
                                    path = [path, tempPath];
                                    path = unique(path);
                                end
                            end
                            
                        case 'BusSelector'
                            % Base case for recursion: Get the exiting
                            % port from the Bus Selector and pass out all
                            % other relevant information
                            object.addToMappedArray('busCreatorBlockMap', creator, get_param(next , 'handle'));
                            outputs = get_param(next, 'OutputSignals');
                            outputs = regexp(outputs, ',', 'split');
                            portNum = find(strcmp(outputs(:), signal));
                            if ~isempty(portNum)
                                temp = get_param(next, 'PortHandles');
                                temp = temp.Outport;
                                exit = [exit temp(portNum)];
                            else
                                for i = 1:length(outputs)
                                    index = strfind(signal, outputs{i});
                                    if ~isempty(index)
                                        if index(1) == 1
                                            temp = get_param(next, 'PortHandles');
                                            temp = temp.Outport;
                                            exit = [exit temp(i)];
                                        end
                                    else
                                        return
                                    end
                                end
                            end
                            
                        case 'Goto'
                            % Follow the bus through Goto blocks
                            object.addToMappedArray('busCreatorBlockMap', creator, get_param(next , 'handle'));
                            froms = findFromsInScopeRCR(object, next, object.gtvFlag);
                            for i = 1:length(froms)
                                outport = get_param(froms{i}, 'PortHandles');
                                outport = outport.Outport;
                                [tempPath, tempExit] = object.traverseBusForwards(creator, outport, ...
                                    signal, path);
                                exit = [exit tempExit];
                                path = [path tempPath];
                                path = unique(path);
                                tag = findVisibilityTagRCR(object, froms{i}, object.gtvFlag);
                                if ~isempty(tag)
                                    object.addToMappedArray('busCreatorBlockMap', creator, get_param(tag, 'Handle'));
                                end
                            end
                            
                        case 'SubSystem'
                            % Follow the bus into Subsystems
                            object.addToMappedArray('busCreatorBlockMap', creator, get_param(next , 'handle'));
                            dstPorts = get_param(portline, 'DstPortHandle');
                            for j = 1:length(dstPorts)
                                if strcmp(get_param(dstPorts(j), 'parent'), getfullname(next))
                                    portNum = get_param(dstPorts(j), 'PortNumber');
                                    inport = find_system(next, 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Inport', 'Port', num2str(portNum));
                                    inportPort = get_param(inport, 'PortHandles');
                                    inportPort = inportPort.Outport;
                                    [path, tempExit] = object.traverseBusForwards(creator, inportPort, ...
                                        signal, path);
                                    exit = [exit tempExit];
                                end
                            end
                            
                        case 'Outport'
                            % Follow the bus out of Subsystems
                            object.addToMappedArray('busCreatorBlockMap', creator, get_param(next , 'handle'));
                            portNum = get_param(next, 'Port');
                            parent = get_param(next, 'parent');
                            if ~isempty(get_param(parent, 'parent'))
                                object.addToMappedArray('busCreatorBlockMap', creator, get_param(parent, 'Handle'));
                                port = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                                    'type', 'port', 'parent', parent, 'PortType', 'outport', 'PortNumber', str2num(portNum));
                                try
                                    connectedBlock = get_param(get_param(port, 'line'), 'DstBlockHandle');
                                catch
                                    break
                                end
                                [path, temp] = object.traverseBusForwards(creator, port, ...
                                    signal, path);
                                exit = [exit temp];
                            end
                            
                        case 'BusToVector'
                            %goes backwards through the bus to find the
                            %port that the signal originates from in the
                            %BusCreator, then use that as the signal num
                            %for traversing the bus
                            object.addToMappedArray('busCreatorBlockMap', creator, get_param(next , 'handle'));
                            nextPorts = get_param(next, 'PortHandles');
                            nextPorts = nextPorts.Outport;
                            exit = [exit nextPorts];
                            
                        otherwise
                            object.addToMappedArray('busCreatorBlockMap', creator, next);
                            nextPorts = get_param(next, 'PortHandles');
                            nextPorts = nextPorts.Outport;
                            [path, temp] = object.traverseBusForwards(creator, nextPorts, ...
                                signal, path);
                            exit = [exit temp];
                    end
                end
            end
        end
        
        function [path, blockList, exit] = traverseBusBackwards(object, iport, signal, path, blockList)
            % TRAVERSEBUSBACKWARDS Go until Bus Creator is encountered. Then,
            % return the path taken there as well as the exiting port.
            %
            %   Inputs:
            %       object      ReachCoreach object.
            %       iport
            %       signal
            %       path
            %       blockList
            %
            %   Outputs:
            %       path
            %       blockList
            %       exit
            
            exit = [];
            for h = length(iport)
                blockList(end + 1) = get_param(get_param(iport(h), 'parent'), 'Handle');
                portLine = get_param(iport(h), 'line');
                srcBlocks = get_param(portLine, 'SrcBlockHandle');
                path(end + 1) = iport(h);
                blockList(end + 1) = portLine;
                
                if isempty(srcBlocks)
                    exit = [];
                    return
                end
                
                next = srcBlocks(1);
                next = get_param(next, 'Handle');
                blockType = get_param(next, 'BlockType');
                nextPorts = get_param(next, 'PortHandles');
                
                % If the bus ends early (not at Bus Selector) output empty
                % dest and exit
                switch blockType
                    case 'BusSelector'
                        %  If another Bus Selector is encountered, call the
                        %  function recursively
                        srcPort = get_param(portLine, 'SrcPortHandle');
                        portNum = get_param(srcPort, 'PortNumber');
                        tempSignal = get_param(next, 'OutputSignals');
                        tempSignal = regexp(tempSignal, ',', 'split');
                        tempSignal = tempSignal{portNum};
                        [path, blockList, intermediate] = object.traverseBusBackwards(nextPorts.Inport, ...
                            tempSignal, path, blockList);
                        path = [path intermediate];
                        for i = 1:length(intermediate)
                            [tempPath, tempBlockList, tempExit] = object.traverseBusBackwards(intermediate(i), ...
                                signal, path, blockList);
                            exit = [exit tempExit];
                            blockList = [blockList tempBlockList];
                            path = [path, tempPath];
                        end
                        
                    case 'BusCreator'
                        % Case where the exit of the current bused signal is
                        % found
                        blockList(end + 1) = next;
                        inputs = get_param(next, 'LineHandles');
                        inputs = inputs.Inport;
                        inputs = get_param(inputs, 'Name');
                        portNum = find(strcmp(signal, inputs));
                        match = regexp(signal, '^signal[1-9]', 'match');
                        if isempty(portNum)&&~isempty(match)
                            portNum = regexp(match{1}, '[1-9]*$', 'match');
                            portNum = str2num(portNum{1});
                        else
                            portNum = 1:length(inputs);
                        end
                        temp = get_param(next, 'PortHandles');
                        temp = temp.Inport;
                        temp = temp(portNum);
                        if ~isempty(regexp(signal, '^(([^\.]*)\.)+[^\.]*$', 'match'))
                            cutoff = strfind(signal, '.');
                            cutoff = cutoff(1);
                            signalName = signal(cutoff+1:end);
                            [tempPath, tempBlockList, tempExit] = object.traverseBusBackwards(temp, ...
                                signalName, path, blockList);
                            exit = [exit tempExit];
                            blockList = [blockList tempBlockList];
                            path = [path, tempPath];
                        else
                            exit = [exit temp];
                        end
                        
                    case 'From'
                        % Follow the bus through From blocks
                        blockList(end + 1) = next;
                        gotos = findGotosInScopeRCR(object, next, object.gtvFlag);
                        for i = 1:length(gotos)
                            gotoPort = get_param(gotos{i}, 'PortHandles');
                            gotoPort = gotoPort.Inport;
                            [tempPath, tempBlockList, tempExit] = object.traverseBusBackwards(gotoPort, ...
                                signal, path, blockList);
                            exit = [exit tempExit];
                            blockList = [blockList tempBlockList];
                            path = [path, tempPath];
                            tag = findVisibilityTagRCR(object, gotos{i}, object.gtvFlag);
                            if ~isempty(tag)
                                blockList(end + 1) = get_param(tag, 'Handle');
                            end
                        end
                        
                    case 'SubSystem'
                        % Follow the bus into Subsystems
                        blockList(end + 1) = next;
                        srcPorts = get_param(portLine, 'SrcPortHandle');
                        for j = 1:length(srcPorts)
                            portNum = get_param(srcPorts(j), 'PortNumber');
                            outport = find_system(next, 'SearchDepth', 1, 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Outport', 'Port', num2str(portNum));
                            outportPort = get_param(outport, 'PortHandles');
                            outportPort = outportPort.Inport;
                            [path, blockList, temp] = object.traverseBusBackwards(outportPort, signal, path, blockList);
                            exit = [exit temp];
                        end
                        
                    case 'Inport'
                        % Follow the bus out of Subsystems or end
                        portNum = get_param(next, 'Port');
                        parent = get_param(next, 'parent');
                        if ~isempty(get_param(parent, 'parent'))
                            blockList(end + 1) = get_param(parent, 'Handle');
                            blockList(end + 1) = get_param(next, 'Handle');
                            port = find_system(get_param(parent, 'parent'), 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'SearchDepth', 1, 'FindAll', 'on', ...
                                'type', 'port', 'parent', parent, 'PortType', 'inport', 'PortNumber', str2num(portNum));
                            path(end + 1) = port;
                            [path, blockList, temp] = object.traverseBusBackwards(port, signal, path, blockList);
                            exit = [exit temp];
                        else
                            blockList(end + 1) = get_param(next, 'Handle');
                        end
                        
                    case 'BusAssignment'
                        % Follow the proper signal in a BusAssignment block
                        assignedSignals = get_param(next, 'AssignedSignals');
                        assignedSignals = regexp(assignedSignals, ',', 'split');
                        inputs = get_param(next, 'PortHandles');
                        inputs = inputs.Inport;
                        for i = 1:length(assignedSignals)
                            if(strcmp(assignedSignals(i), signal))
                                exit = [exit inputs(1 + i)];
                            end
                        end
                        [path, blockList, temp] = object.traverseBusBackwards(inputs(1), signal, path, blockList);
                        exit = [exit temp];
                        
                    otherwise
                        blockList(end + 1) = next;
                        [path, blockList, temp] = object.traverseBusBackwards(nextPorts.Inport, signal, path, blockList);
                        exit = [exit temp];
                end
            end
        end
        
        function addToMappedArray(object, property, key, handle)
            % ADDTOMAPPEDARRAY
            %
            %   Inputs:
            %       object      ReachCoreach object.
            %       property
            %       key
            %       handle
            %
            %   Outputs:
            %
            
            eval(['temp = object.' property ';']);
            try
                array = temp(key);
            catch
                array = [];
            end
            array(end + 1) = handle;
            array = unique(array);
            temp(key) = array;
            eval(['object.' property ' = temp;']);
        end
        
    end
end